package demo.controller;

import cn.hutool.core.bean.BeanUtil;
import demo.Result;
import demo.dto.*;
import demo.entity.Bonus;
import demo.entity.User;
import demo.entity.UserCompany;
import demo.service.*;
import demo.util.DateUtil;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 肖溥博文
 * @version 1.5
 */
@RestController
public class SalaryController {

    @Autowired
    SalaryService salaryService;
    @Autowired
    UserService userService;
    @Autowired
    UserCompanyService userCompanyService;
    @Autowired
    CompanyService companyService;
    @Autowired
    BonusService bonusService;

    /**
     * 设置薪资
     *
     * @param requestSetSalaryDto 必须包含被操作用户的 uid 和薪资金额
     * @return 结果对象，成功时返回 Salary 对象
     */
    @PostMapping("/setSalary")
    @RequiresAuthentication
    @RequiresRoles("HR")
    public Result setSalary(@Validated @RequestBody RequestSetSalaryDto requestSetSalaryDto) {
        Long uid = requestSetSalaryDto.getUid();

        User user = userService.findUserByUid(uid);
        if (user == null) {
            return Result.error("用户不存在，无法设置薪资");
        }

        Result resultUserCompanyToSet = userCompanyService.findLatestUserCompanyByUid(uid);
        if (resultUserCompanyToSet.getCode() != 200) {
            return Result.error("用户不在职，无法设置薪资");
        }

        return salaryService.setSalary(requestSetSalaryDto.getAmount(), ((UserCompany) resultUserCompanyToSet.getData()).getId());
    }

    /**
     * 按 用户 id 查找该用户现在的工资
     *
     * @return 当用户不存在或不在职返回 error
     */
    @PostMapping("/getSalaryByUid")
    @RequiresAuthentication
    public Result getSalaryByUid(@Validated @RequestBody RequestWithLongDto requestWithLongDto) {
        User user = userService.findUserByUid(requestWithLongDto.getId());
        if (user == null) {
            return Result.error("用户不存在，无法查找当前用户薪资");
        }

        Result resultUserCompanyToSet = userCompanyService.findLatestUserCompanyByUid(user.getUid());
        if (resultUserCompanyToSet.getCode() != 200) {
            return Result.error("用户不在职，没有薪资");
        }
        return salaryService.getSalaryByUserCompanyId(((UserCompany) resultUserCompanyToSet.getData()).getId());
    }

    @PostMapping("/getSalariesByUid")
    @RequiresAuthentication
    public Result getSalariesByUid(@Validated @RequestBody RequestWithLongDto requestWithLongDto) {
        User user = userService.findUserByUid(requestWithLongDto.getId());
        if (user == null) {
            return Result.error("用户不存在，无法查找当前用户的历史薪资");
        }

        return salaryService.getSalariesByUid(requestWithLongDto.getId());
    }

    /**
     * 添加奖金/津贴
     *
     * @param requestAddBonusDto (1) 用户 id、(2) 奖金理由、(3) 奖金类型（"bonus" 或 "subsidy"）和 (4) 奖金金额。
     * @return 结果对象，包含一个 bonus 对象
     */
    @PostMapping("/addBonus")
    @RequiresAuthentication
    @RequiresRoles("HR")
    Result addBonus(@Validated @RequestBody RequestAddBonusDto requestAddBonusDto) {
        if (userService.findUserByUid(requestAddBonusDto.getUid()) == null) {
            return Result.error("用户不存在，无法添加奖金");
        }

        Result resultUserCompanyToSet = userCompanyService.findLatestUserCompanyByUid(requestAddBonusDto.getUid());
        if (resultUserCompanyToSet.getCode() != 200) {
            return Result.error("用户不在职，没有薪资");
        }

        UserCompany userCompany = (UserCompany) resultUserCompanyToSet.getData();
        return bonusService.addBonus(userCompany.getId(),
            requestAddBonusDto.getAmount(),
            requestAddBonusDto.getType(),
            requestAddBonusDto.getReason()
        );
    }

    /**
     * 在原有奖金记录上修改
     *
     * @param requestSetBonusDto (1) 奖金 id、(2) 奖金理由和 (3) 奖金金额
     * @return 结果对象
     */
    @PostMapping("/setBonus")
    @RequiresAuthentication
    @RequiresRoles("HR")
    public Result setBonus(@Validated @RequestBody RequestSetBonusDto requestSetBonusDto) {
        Result result = bonusService.findByBonusId(requestSetBonusDto.getId());
        if (result.getCode() != 200) {
            return result;
        }

        Bonus bonus = (Bonus) result.getData();
        return bonusService.setBonus(bonus, requestSetBonusDto.getAmount(), requestSetBonusDto.getReason());
    }

    /**
     * 删除奖金
     *
     * @param requestWithLongDto 必须含有一个奖金 id 的 RequestWithLongDto 对象
     * @return 结果对象
     */
    @PostMapping("/deleteBonus")
    @RequiresAuthentication
    @RequiresRoles("HR")
    Result deleteBonus(@Validated @RequestBody RequestWithLongDto requestWithLongDto) {
        Result result = bonusService.findByBonusId(requestWithLongDto.getId());
        if (result.getCode() != 200) {
            return result;
        }

        Bonus bonus = (Bonus) result.getData();
        return bonusService.deleteBonus(bonus);
    }

    /**
     * 查询用户在本司本月奖金
     *
     * @param requestGetMonthBonusDto 必须传入用户 id 和奖金类型
     * @return 返回该用户所有在本司本月的奖金记录
     */
    @PostMapping("/getMonthBonus")
    @RequiresAuthentication
    Result getMonthBonus(@Validated @RequestBody RequestGetMonthBonusDto requestGetMonthBonusDto) {
        Long uid = requestGetMonthBonusDto.getUid();
        if (userService.findUserByUid(uid) == null) {
            return Result.error("用户不存在，无法查询奖金");
        }

        UserCompany latestUserCompany = (UserCompany) userCompanyService.findLatestUserCompanyByUid(uid).getData();
        if (latestUserCompany == null) {
            return Result.error("用户不在职，无法查询当月奖金");
        }

        User user = new User();
        user.setUid(uid);
        List<UserCompany> userCompanies = userCompanyService.listUserCompanies(user);

        List<ResponseBonusDto> responseBonusDtos = new ArrayList<>();

        for (UserCompany userCompany : userCompanies) {
            if (userCompany.getCompanyId().equals(latestUserCompany.getCompanyId())) {
                List<Bonus> bonuses = (List<Bonus>)
                    bonusService.listBonusesByUserCompanyId(userCompany.getId(), requestGetMonthBonusDto.getType()).getData();
                for (Bonus bonus : bonuses) {
                    ResponseBonusDto responseBonusDto = new ResponseBonusDto();
                    BeanUtil.copyProperties(bonus, responseBonusDto);
                    responseBonusDto.setDate(DateUtil.formatToMinute(bonus.getDate()));
                    responseBonusDto.setBonusId(bonus.getId());
                    responseBonusDtos.add(responseBonusDto);
                }
            }
        }

        return Result.success("查找成功", responseBonusDtos);
    }
}
